package com.srong.nio.react;

import com.sorng.nio.PropertiesUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Executor;

@Slf4j
public class JavaClient {
    public static volatile boolean isInterrupted = false;

    private static final Executor executor = Runnable::run;

    public static void main(String[] args) {


        //change 1
        //change 2
        try {


            SocketChannel channel = SocketChannel.open();
            Selector selector = Selector.open();
            doConnect(channel, selector);


            channel.configureBlocking(false);
            channel.socket().setReuseAddress(true);
            channel.socket().setReceiveBufferSize(1024);
            channel.socket().setSendBufferSize(1024);


            while (!isInterrupted) {


                int select = selector.select(1000);
                Set<SelectionKey> selectionKeys = selector.selectedKeys();
                Iterator<SelectionKey> iterator = selectionKeys.iterator();

                while (iterator.hasNext()) {
                    final SelectionKey key = iterator.next();

                    if (key.isConnectable()) {
                        log.info("连接成功...");
                        executor.execute(getConnectRunnable(key));
                    }

                    if (key.isReadable()) {
                        executor.execute(getReadRunnable(key));
                    }


                }

            }


        } catch (IOException e) {
            e.printStackTrace();
        } catch (UnresolvedAddressException e) {
            log.error("解析地址失败", e);

        }
    }

    /**
     * 获取读取任务runnable
     */
    private static Runnable getReadRunnable(SelectionKey key) {
        return () -> {
            try {
                SocketChannel channel = (SocketChannel) key.channel();
                log.info("当前可读信息！");
                ByteBuffer buffer = ByteBuffer.allocate(1024);
                channel.read(buffer);
                String message = new String(buffer.array());
                log.info("接收到消息{}", message);
            } catch (IOException e) {
                log.error("读取时IO异常", e);
            }

        };
    }

    /**
     * 获取处理连接的runnable
     */
    private static Runnable getConnectRunnable(SelectionKey key) {
        return () -> {
            try {

                Selector childSelector = key.selector();
                SocketChannel childChanel = (SocketChannel) key.channel();

                if (childChanel.finishConnect()) {
                    childChanel.register(childSelector, SelectionKey.OP_READ);
                }

            } catch (ClosedChannelException e) {
                log.error("channel异常", e);
            } catch (IOException e) {
                e.printStackTrace();
            }

        };
    }

    /**
     * 执行连接操作
     */
    private static void doConnect(SocketChannel channel, Selector selector) throws IOException {

        Properties properties = PropertiesUtil.getProperties(
                JavaClient.class,
                "conf.properties"
        );

        channel.configureBlocking(false);

        InetSocketAddress addr = new InetSocketAddress(
                properties.getProperty("remote.host"),
                Integer.parseInt(properties.getProperty("remote.port"))
        );
        channel.connect(addr);
        channel.register(selector, SelectionKey.OP_CONNECT);
//        if (!channel.connect(addr)) {
//            log.error("连接失败");
//            System.exit(1);
//        }
        log.info("绑定成功！");

    }


}
